﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using Estructuras.Comunes;
using Estructuras.Estructura;

namespace Estructuras.Funciones.Transformar
{
    public static partial class Transformar
    {
        /// <summary>
        /// Transforma los datos de entrada en base a las funciones predefinidas seleccionadas.
        /// </summary>
        /// <param name="entrada">Fichero de datos de entrada</param>
        /// <param name="salida">Fichero de datos de salida</param>
        /// <param name="funciones">Listado de funciones a aplicar</param>
        /// <param name="camposOrigen">Campos orígen de cada una de las funciones a aplicar</param>
        /// <param name="camposDestino">Campos destino de cada una de las funciones a aplicar</param>
        /// <param name="parametros">Lista de parámetros de cada función</param>
        /// <param name="formatoEntrada">Estructura de los datos de entrada</param>
        /// <param name="formatoSalida">Estructura de los datos de salida</param>
        /// <returns>Número de registros transformados</returns>
        public static long TransformarCondicional(TextReader entrada, TextWriter salida, 
            List<string> condiciones, List<string> camposCondiciones, List<List<string>> parametrosCondiciones,
            List<string> funcionesVerdadero, List<string> camposOrigenVerdadero, List<string> camposDestinoVerdadero, List<List<string>> parametrosVerdadero,
            List<string> funcionesFalso, List<string> camposOrigenFalso, List<string> camposDestinoFalso, List<List<string>> parametrosFalso,
            Estructura.Estructura formatoEntrada, Estructura.Estructura formatoSalida)
        {
            try
            {
                long filasProcesadas = 0;
                if (condiciones.Count != camposCondiciones.Count)
                    throw new Excepcion(Constantes.ErrorNumeroCondicionesYCamposNoCoinciden, Constantes.CodigoErrorNumeroCondicionesYCamposNoCoinciden);
                if (condiciones.Count != parametrosCondiciones.Count)
                    throw new Excepcion(Constantes.ErrorNumeroCondicionesYParametrosNoCoinciden, Constantes.CodigoErrorNumeroCondicionesYParametrosNoCoinciden);

                if (funcionesVerdadero.Count != camposOrigenVerdadero.Count)
                    throw new Excepcion(Constantes.ErrorNumeroFuncionesYCamposOrigenNoCoincidenVerdadero, Constantes.CodigoErrorNumeroFuncionesYCamposOrigenNoCoincidenVerdadero);
                if (funcionesVerdadero.Count != camposDestinoVerdadero.Count)
                    throw new Excepcion(Constantes.ErrorNumeroFuncionesYCamposDestinoNoCoincidenVerdadero, Constantes.CodigoErrorNumeroFuncionesYCamposDestinoNoCoincidenVerdadero);
                if (funcionesVerdadero.Count != parametrosVerdadero.Count)
                    throw new Excepcion(Constantes.ErrorNumeroFuncionesYParametrosNoCoincidenVerdadero, Constantes.CodigoErrorNumeroFuncionesYParametrosNoCoincidenVerdadero);

                if (funcionesFalso.Count != camposOrigenFalso.Count)
                    throw new Excepcion(Constantes.ErrorNumeroFuncionesYCamposOrigenNoCoincidenFalso, Constantes.CodigoErrorNumeroFuncionesYCamposOrigenNoCoincidenFalso);
                if (funcionesFalso.Count != camposDestinoFalso.Count)
                    throw new Excepcion(Constantes.ErrorNumeroFuncionesYCamposDestinoNoCoincidenFalso, Constantes.CodigoErrorNumeroFuncionesYCamposDestinoNoCoincidenFalso);
                if (funcionesFalso.Count != parametrosFalso.Count)
                    throw new Excepcion(Constantes.ErrorNumeroFuncionesYParametrosNoCoincidenFalso, Constantes.CodigoErrorNumeroFuncionesYParametrosNoCoincidenFalso);

                string linea = entrada.ReadLine();
                while (linea != null)
                {
                    if (linea.Length != formatoEntrada.LongitudRegistro)
                        throw new Excepcion(Constantes.ErrorLongitudRegistroYFormatoNoCoinciden, Constantes.CodigoErrorLongitudRegistroYFormatoNoCoinciden);

                    string nuevoRegistro = formatoSalida.nuevoRegistro(linea, formatoEntrada);
                    int i = 0;
                    foreach (string funcion in condiciones)
                    {
                        if (FuncionesCondicion.EjecutarComprobacion(formatoSalida, ref nuevoRegistro,
                            camposCondiciones[i], funcion, parametrosCondiciones[i]))
                        {
                            if (!string.Empty.Equals(funcionesVerdadero[i]))
                                FuncionesTransformacion.EjecutarFuncion(formatoSalida, ref nuevoRegistro, camposOrigenVerdadero[i],
                                    camposDestinoVerdadero[i], funcionesVerdadero[i], parametrosVerdadero[i]);
                        }
                        else
                        {
                            if (!string.Empty.Equals(funcionesFalso[i]))
                                FuncionesTransformacion.EjecutarFuncion(formatoSalida, ref nuevoRegistro, camposOrigenFalso[i],
                                    camposDestinoFalso[i], funcionesFalso[i], parametrosFalso[i]);
                        }   
                        i++;
                    }
                    salida.WriteLine(nuevoRegistro);
                    linea = entrada.ReadLine();
                    filasProcesadas++;
                }
                return filasProcesadas;
            }
            catch (Excepcion ex)
            {
                throw ex;
            }
            catch (Exception ex)
            {
                throw new Excepcion(Constantes.ErrorTransformarDatos + ex.Message, Constantes.CodigoErrorTransformarDatos);
            }
        }
    }
}
